<?php
namespace cubox\model;

trait Tree{

    static private array $treeAllData = array();
    static private array $tempAllData = array();
    protected string $treeCacheName =  '';
    protected string $treeParentKey =  'parent_id';
    protected string $treeOrderKey  =  'sort';
    protected string $treeOrderDir  =  'asc';
    protected string $treeSearchType  =  'ALL';
    

    /**
     * 获取树形数据
     * 
     * @param int $parent_id
     * @param bool $cacheLab
     * @return array
     */
    public function getTreeData($parent_id,$cacheLab=false,$root = true){
     
        //读取缓存
        if ($cacheLab && $this->treeCacheName!=''){
            $cache =  $this->app->cache();
            $name = $this->treeCacheName.':tree.'.$parent_id;

            if ($cache->exists($name)){
                return json_decode($cache->get($name),true);
            }
        }

        $this->initTreeData();

        if ($root) self::$tempAllData = self::$treeAllData;
        
        $list = $this->getTreeChildren($parent_id);
         
        if (!empty($list)){
            foreach($list as $key=>$val){
                 
                $val =  $this->filterTreeData($val);
                if ($val!==false){
                    $val['children'] = $this->getTreeData($val[$this->key],false,false);
                    $list[$key] =  $val;
                }
            }
        }
        

        //保存缓存
        if ($cacheLab && $this->treeCacheName!=''){
            $cache =  $this->app->cache();
            $name = $this->treeCacheName.':tree.'.$parent_id;
            $cache->set($name,json_encode($list));
        }

        return $list;
    }

    /**
     * 获取树形列表
     * 
     * @return array
     */
    public function getTreeList($parent_id,$cacheLab=false,$root = true):array{
        //读取缓存
        if ($cacheLab && $this->treeCacheName!=''){
            $cache =  $this->app->cache();
            $name = $this->treeCacheName.':list.'.$parent_id;

            if ($cache->exists($name)){
                return json_decode($cache->get($name),true);
            }
        }

        $this->initTreeData();
       
        if ($root) self::$tempAllData = self::$treeAllData;


        $list = $this->getTreeChildren($parent_id);
         
        if (!empty($list)){
            foreach($list as $key=>$val){
                if ($val!==false){
                    $list = array_merge($list, $this->getTreeList($val[$this->key],false,false));
                }
            }
        }
        
        //保存缓存
        if ($cacheLab && $this->treeCacheName!=''){
            $cache =  $this->app->cache();
            $name = $this->treeCacheName.':list.'.$parent_id;
            $cache->set($name,json_encode($list));
        }

        return $list;
    }


    /**
     * 获取所有子集ID
     * 
     * @param int $parent_id 父ID
     * @param bool $hasSelf  是否包涵自己
     * @param bool $cacheLab  是否缓存
     * @return array
     */
    public function getKeyCollect($parent_id,$hasSelf = true,$cacheLab=false):array{
        $list = $this->getTreeList($parent_id,$cacheLab);

        $re = [];

        if ($hasSelf) $re[] = $parent_id;

        foreach($list as $key => $row){
            $re[] = $row[$this->key];
        }

        return $re;
    }

 
    private function getTreeChildren($parent_id){

        if ($this->treeSearchType == 'ALL'){
            $list =  self::$tempAllData;
            $re= array();
            
            foreach($list as $key=>$val){
                if ($val[$this->treeParentKey]==$parent_id){
                    $re[] =  $val;
                    unset(self::$tempAllData[$key]);
                }
            }
        }else{
            $re = $this->where($this->treeParentKey,'=',$parent_id)->order($this->treeOrderKey,$this->treeOrderDir)->getData();
        }
       
        return $re;
    }


    public function getTreePath($parent_id):array{
        if ($parent_id == 0) return [];
        $this->initTreeData();
        $row = null;
        if ($this->treeSearchType == 'ALL'){
            
            if (empty(self::$tempAllData)){
                self::$tempAllData = self::$treeAllData;
            }
 
            foreach(self::$tempAllData as $key=>$val){
                 
                if ($val[$this->key]==$parent_id){
                    $row =  $val;
                     
                    unset(self::$tempAllData[$key]);
                }
            }

        }else{
            $row = $this->getId($parent_id);
        }

        if ($row){
            if ($row[$this->treeParentKey]!=0){
                $re = $this->getTreePath($row[$this->treeParentKey]);
            }else{
                self::$tempAllData =  array();
                $re = array();
            }
            
            $re[] = $row;
            return $re;
        }else{
            return array();
        }
    }


    public function clearTreeCache($parent_id=0){
        self::$treeAllData = array();
        $cache =  $this->app->cache();
        $cache->delete($this->treeCacheName.':tree.'.$parent_id);
        $cache->delete($this->treeCacheName.':list.'.$parent_id);
    }

    protected function initTreeData(){
        if ($this->treeSearchType == 'ALL' && empty(self::$treeAllData)){ 
            self::$treeAllData = $this->order($this->treeOrderKey,$this->treeOrderDir)->getData();   
        }
    }

    protected function filterTreeData($data){
        return $data;
    }

     
    public function updateTreeChildrenOrder($parent_id){
        $list =  $this->where($this->treeParentKey,'=',$parent_id)->order($this->treeOrderKey,'asc')->getData();

        if (!empty($list)){
            foreach($list as $key=>$row){
                $this->updateId($row[$this->key],[$this->treeOrderKey=>$key]);
            }
            
        }
        
    }

    public function getTreeChildrenCount($parent_id){
       return $this->where($this->treeParentKey,'=',$parent_id)->count();
    }

    
}